package com.selebash;

import com.selebash.config.Config;
import com.selebash.exception.SelebashException;
import com.selebash.runtime.ExecutionContext;
import com.selebash.runtime.resource.FileResourceManager;
import com.selebash.runtime.resource.JarResourceManager;
import com.selebash.scripts.Script;
import java.io.File;
import org.apache.commons.io.FilenameUtils;

/**
 * @author sad
 */
public class Selebash {

    private Config config;
    private String basePath;

    public Selebash setConfig(Config config) {
        this.config = config;
        return this;
    }

    private String getSiblingPath(String filePath, String newFileName, ExecutionContext context) {
        String path = FilenameUtils.getFullPath(filePath);
        return context.getResourceManager().combinePath(path, newFileName);
    }

    private String stripPath(String filePath) {
        return FilenameUtils.getBaseName(filePath);
    }

    private String addExtension(String path) {
        if (path.toLowerCase().endsWith(".sbh")) {
            return path;
        }
        return path + ".sbh";
    }

    private void init() {
        if (config == null) {
            config = new Config();
        }
    }

    public ExecutionContext parseFile(File file) {
        ExecutionContext context = new ExecutionContext();
        context.setConfig(config);
        context.setResourceManager(new FileResourceManager());
        parse(file.getAbsolutePath(), context);
        return context;
    }

    public ExecutionContext parseFromJarResource(String path) {
        ExecutionContext context = new ExecutionContext();
        context.setConfig(config);
        context.setResourceManager(new JarResourceManager());
        parse(path, context);
        return context;
    }

    private void parse(String path, ExecutionContext context) {
        init();
        if (!context.getResourceManager().isExist(path)) {
            throw new SelebashException("Cannot find script:" + path);
        }

        basePath = FilenameUtils.getPrefix(path) + FilenameUtils.getPath(path);
        String scriptName = stripPath(path);
        Script script = parseScriptFile(path, scriptName, context);
        context.setMainScript(script);
        context.getScriptMap().put(scriptName, script);
        Script tempScript = script;
        while (tempScript != null && tempScript.getTemplate() != null) {
            if (context.getScriptMap().get(tempScript.getTemplate()) != null) {
                tempScript.setParentScript(context.getScriptMap().get(tempScript.getTemplate()));
                break;
            } else {
                String newPath = getSiblingPath(path, addExtension(tempScript.getTemplate()), context);
                Script newScript = parseScriptFile(newPath, tempScript.getTemplate(), context);
                String newScriptName = stripPath(new File(newPath).getAbsolutePath());
                tempScript.setParentScript(newScript);
                context.getScriptMap().put(newScriptName, script);
                tempScript = newScript;
            }
        }
    }

    private Script parseScriptFile(String file, String scriptName, ExecutionContext context) {
        SelebashParser parser = new SelebashParser(config);
        String src = context.getResourceManager().getContent(file);
        Script script = parser.parse(src, scriptName);
        return script;
    }

    public ExecutionContext parse(String src, String filePath) {
        init();
        SelebashParser parser = new SelebashParser(config);
        Script script = parser.parse(src, filePath);
        ExecutionContext context = new ExecutionContext();
        context.setConfig(config);
        context.getScriptMap().put(filePath, script);
        return context;
    }
}
